package controllers

import (
	"encoding/json"
	"errors"
	beego "github.com/beego/beego/v2/server/web"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
	"log"
	"math"
	"mime/multipart"
	"path/filepath"
	"pet_management/models"
	"strconv"
	"time"
)

type PetControllers struct {
	beego.Controller
}

type Res struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

func (c *PetControllers) Register() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	username := c.GetString("username")
	password := c.GetString("password")
	peopleName := c.GetString("peoplename")

	passwordMd5 := MD5(password)
	user := models.UserInfo{
		Model:      gorm.Model{},
		Username:   username,
		Password:   passwordMd5,
		PeopleName: peopleName,
	}
	err := models.DB.Create(&user).Error
	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "注册失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	} else {
		c.Data["json"] = Res{
			Code: 200,
			Msg:  "注册成功",
			Data: nil,
		}
		_ = c.ServeJSON()
	}
}

func (c *PetControllers) Login() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	username := c.GetString("username")
	password := c.GetString("password")

	passwordMD5 := MD5(password)

	var user models.UserInfo

	err := models.DB.Where("username = ?", username).First(&user).Error
	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "用户名不存在",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	count, err1 := models.Rdb.Get(models.Ctx, "user:login:"+username).Int()
	if err1 != nil {
		if err1 == redis.Nil {
			count = 0
		}
	}

	if count >= 3 {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "密码错误已达到3次，请2小时候再试",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	if passwordMD5 != user.Password {
		_ = models.Rdb.Set(models.Ctx, "user:login:"+username, count+1, time.Hour*2).Err()
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "用户密码错误，请重新输入",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	} else {
		_ = models.Rdb.Set(models.Ctx, "user_login:"+username, 0, 0).Err()
		c.Data["json"] = Res{
			Code: 200,
			Msg:  "登录成功",
			Data: nil,
		}
		_ = c.ServeJSON()
	}
}

func (c *PetControllers) CateAdd() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	cateName := c.GetString("catename")

	petCate := models.PetCate{
		Model:    gorm.Model{},
		CateName: cateName,
	}

	err := models.DB.Create(&petCate).Error
	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "宠物分类添加失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	} else {
		c.Data["json"] = Res{
			Code: 200,
			Msg:  "宠物分类添加成功",
			Data: nil,
		}
		_ = c.ServeJSON()
	}
}

func (c *PetControllers) PetAdd() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	petName := c.GetString("petname")
	petSex := c.GetString("petsex")
	petAge, _ := c.GetInt("petage")
	img, header, err := c.GetFile("img")
	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "图片获取失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}
	defer func(img multipart.File) {
		err = img.Close()
		if err != nil {

		}
	}(img)

	ImgType := map[string]bool{
		".png":  true,
		".jpg":  true,
		".jpeg": true,
	}

	if !ImgType[filepath.Ext(header.Filename)] {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "禁止上传非图片文件",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	size := float64(header.Size) / 1024 / 1024

	if size > 1 {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "禁止上传大于1M的图片",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	path := "static/img" + header.Filename

	err = c.SaveToFile("img", path)

	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "图片保存失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	pet := models.PetInfo{
		Model:   gorm.Model{},
		PetName: petName,
		PetSex:  petSex,
		PetAge:  petAge,
		Img:     "http://127.0.0.1:8080/" + path,
	}

	err = models.DB.Create(&pet).Error
	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "宠物信息添加失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	} else {
		c.Data["json"] = Res{
			Code: 200,
			Msg:  "宠物信息添加成功",
			Data: nil,
		}
		_ = c.ServeJSON()
	}
}

func (c *PetControllers) PetList() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	page, _ := c.GetInt("page", 1)
	size, _ := c.GetInt("size", 5)

	offset := (page - 1) * size
	var count int64
	models.DB.Model(&models.PetInfo{}).Count(&count)
	log.Println(count)
	sum := int(math.Ceil(float64(count) / float64(size)))

	up := page - 1
	if up < 1 {
		up = page
	}
	down := page + 1
	if down > sum {
		down = page
	}
	var pet []models.PetInfo
	// 先进行redis缓存查询
	redisRes, err := models.Rdb.Get(models.Ctx, "pet:page"+strconv.Itoa(page)+"_offset"+strconv.Itoa(size)).Result()

	if errors.Is(err, redis.Nil) || redisRes == "" { // 没有这个键或者没有结果
		//进行mysql查询
		err = models.DB.Limit(size).Offset(offset).Find(&pet).Error
		if err != nil {
			c.Data["json"] = Res{
				Code: 400,
				Msg:  "宠物列表查询失败",
				Data: nil,
			}
			_ = c.ServeJSON()
			return
		} else {
			log.Println("当前结果从mysql获取")
			// mysql查询成功，将结果存入redis
			marshal, _ := json.Marshal(pet)
			_ = models.Rdb.Set(models.Ctx, "pet:page"+strconv.Itoa(page)+"_offset"+strconv.Itoa(size), marshal, time.Hour*2).Err()

			info := map[string]interface{}{
				"data": pet,
				"sum":  sum,
				"up":   up,
				"down": down,
			}

			c.Data["json"] = Res{
				Code: 200,
				Msg:  "宠物列表查询成功",
				Data: info,
			}
			_ = c.ServeJSON()
		}
	} else { // redis中有结果，直接返回
		log.Println("当前结果从redis获取")
		_ = json.Unmarshal([]byte(redisRes), &pet)

		info := map[string]interface{}{
			"data": pet,
			"sum":  sum,
			"up":   up,
			"down": down,
		}

		c.Data["json"] = Res{
			Code: 200,
			Msg:  "宠物列表查询成功",
			Data: info,
		}
		_ = c.ServeJSON()
	}
}

func (c *PetControllers) PetInfo() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	id := c.GetString("id")

	var pet models.PetInfo

	// 先进行redis缓存查询
	redisRes, err := models.Rdb.Get(models.Ctx, "pet:id:"+id).Result()

	if errors.Is(err, redis.Nil) || redisRes == "" { // 没有这个键或者没有结果
		//进行mysql查询
		err = models.DB.Where("id = ?", id).Find(&pet).Error
		if err != nil {
			c.Data["json"] = Res{
				Code: 400,
				Msg:  "宠物详情查询失败",
				Data: nil,
			}
			_ = c.ServeJSON()
			return
		} else {
			log.Println("当前结果从mysql获取")
			// mysql查询成功，将结果存入redis
			marshal, _ := json.Marshal(pet)
			_ = models.Rdb.Set(models.Ctx, "pet:id:"+id, marshal, time.Hour*2).Err()

			c.Data["json"] = Res{
				Code: 200,
				Msg:  "宠物详情查询成功",
				Data: pet,
			}
			_ = c.ServeJSON()
		}
	} else { // redis中有结果，直接返回
		log.Println("当前结果从redis获取")
		_ = json.Unmarshal([]byte(redisRes), &pet)

		c.Data["json"] = Res{
			Code: 200,
			Msg:  "宠物详情查询成功",
			Data: pet,
		}
		_ = c.ServeJSON()
	}
}

func (c *PetControllers) Del() {
	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	username := c.GetString("username")
	password := c.GetString("password")
	id, _ := c.GetInt("id")

	var user models.UserInfo
	err := models.DB.Where("username = ?", username).First(&user).Error

	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "不存在此用户,删除失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}
	// 这里存在一个问题，当前未设置密码失败最大次数，可以利用此接口来爆破密码
	if MD5(password) != user.Password {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "用户密码不正确，删除失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	if user.PetId != id {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "不是您的宠物，删除失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	}

	err = models.DB.Delete(&models.PetInfo{}, id).Error
	if err != nil {
		c.Data["json"] = Res{
			Code: 400,
			Msg:  "删除失败",
			Data: nil,
		}
		_ = c.ServeJSON()
		return
	} else {
		c.Data["json"] = Res{
			Code: 200,
			Msg:  "删除成功",
			Data: nil,
		}
		_ = c.ServeJSON()
	}
}
